import re

from rest_framework_jwt.settings import api_settings

from celery_tasks.email.tasks import send_verify_mail
from users import constants
from utils import tjws
from .models import User, Address
from rest_framework import serializers
from django_redis import get_redis_connection


class CreateUserSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    token = serializers.CharField(read_only=True)
    mobile = serializers.CharField()
    sms_code = serializers.CharField(write_only=True)
    allow = serializers.CharField(write_only=True)
    username = serializers.CharField(
        min_length=5,
        max_length=20,
        error_messages={
            'min_length': '用户名为5-20个字符',
            'max_length': '用户名为5-20个字符'
        }
    )
    password = serializers.CharField(
        write_only=True,
        min_length=8,
        max_length=20,
        error_messages={
            'min_length': '密码为8-20个字符',
            'max_length': '密码为8-20个字符'
        }
    )
    password2 = serializers.CharField(
        write_only=True,
        min_length=8,
        max_length=20,
        error_messages={
            'min_length': '密码为8-20个字符',
            'max_length': '密码为8-20个字符'
        }
    )

    def validate_username(self, value):
        if User.objects.filter(username=value).count() > 0:
            raise serializers.ValidationError("用户名已经存在")
        return value

    def validate_mobile(self, value):
        if not re.match(r'1[3-9]\d{9}', value):
            raise serializers.ValidationError("手机号码格式不正确")

        if User.objects.filter(mobile=value).count() > 0:
            raise serializers.ValidationError("手机号码已经注册过了")
        return value

    def validate_allow(self, value):
        if not value:
            raise serializers.ValidationError("需要同意协议才可以注册")
        return value

    def validate(self, attrs):
        # 短信验证码
        # 首先连接redis
        redis_cli = get_redis_connection('sms_code')
        key = 'sms_code_' + attrs.get('mobile')  # 'sms_code_mobile'
        # 获取redis里面的验证码
        sms_code_redis = redis_cli.get(key)
        if not sms_code_redis:
            raise serializers.ValidationError("验证码已经过期")
        # 删除redis里面的验证码
        redis_cli.delete(key)
        sms_code_request = attrs.get('sms_code')
        if int(sms_code_request) != int(sms_code_redis):
            print(int(sms_code_request))
            print(int(sms_code_redis))
            raise serializers.ValidationError("验证码错误")

        # 判断密码
        if attrs.get('password') != attrs.get('password2'):
            raise serializers.ValidationError("两次密码不一致")

        return attrs

    # 使用create方法直接创建和保存并返回用户，注意字段
    def create(self, validated_data):
        user = User()
        user.username = validated_data.get('username')
        user.mobile = validated_data.get('mobile')
        user.set_password(validated_data.get('password'))
        user.save()

        # 需要生成token
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)  # header.payload.signature

        # 将token输出到客户端
        user.token = token

        return user


class UserDetailSerializer(serializers.ModelSerializer):
    """用户中心序列化器"""

    class Meta:
        model = User
        fields = ['id', 'username', 'mobile', 'email', 'email_active']


class EmailSerializer(serializers.ModelSerializer):
    """邮箱序列化器"""

    class Meta:
        model = User
        fields = ['email']

    def update(self, instance, validated_data):
        # 保存邮箱属性
        email = validated_data.get('email')
        instance.email = email
        instance.save()
        # 发送url验证
        send_verify_mail.delay(email, instance.generate_verify_email_token())

        # 返回instance
        return instance


class EmailActiveSerializer(serializers.Serializer):
    token = serializers.CharField(max_length=200)

    def validate(self, attrs):
        # 获取token
        token = attrs.get('token')
        # 解密token
        data_dict = tjws.loads(token, constants.USER_EMAIL_TOKEN_EXPIRES)
        if data_dict is None:
            # 验证  如果取不到就报错
            raise serializers.ValidationError("邮箱链接邮件过期")
        # 取出user_id
        user_id = data_dict.get('user_id')
        # 存到attrs里面
        attrs['user_id'] = user_id
        # 返回
        return attrs


class AddressSerializer(serializers.ModelSerializer):
    # 关系属性要自己定义，改成用id接收
    # 这个是我们接收的,但是也会输出
    province_id = serializers.IntegerField()
    city_id = serializers.IntegerField()
    district_id = serializers.IntegerField()

    # 关系属性要改成非必须输入
    # 这个是我们只用于输出的，不会接收数据，因为我们接收的是上面地址的id号,前端传过来的是id
    province = serializers.CharField(read_only=True)
    city = serializers.CharField(read_only=True)
    district = serializers.CharField(read_only=True)

    # 上面的都是关系属性，下面这个才是我们输出的内容，上面的都是添加的, 接收的时候只会接收id,输出的时候输出id和字符串
    class Meta:
        model = Address
        # user不需要传递 而是获取当前用户
        # 写exclude表示除了这些，剩下的都需要展示
        exclude = ['is_delete', 'create_time', 'update_time', 'user']

    # 为什么要重写create是因为不传递user我们需要获取当前登录的user，因为一个地址需要属于一个user，这个必须传
    # 同时因为是外键，不传就不能确定关系，所以一定会报错
    def create(self, validated_data):
        # 默认会向序列化器对象的context属性补充三个数据，request,view,format，这个request正是我需要的，为了能获取到登录的user
        user = self.context['request'].user
        if user.addresses.filter(is_delete=False).count() > constants.ADDRESS_LIMIT:
            raise serializers.ValidationError("已经超过允许设置地址数量的上限")
        # 默认实现中，未指定属性user，则添加时必然报错，所以在添加前需要指定user属性
        # 创建一个地址需要添加一个用户表示这个地址属于这个用户，地址有一个外键叫user
        validated_data['user'] = user
        # 调用父类的方法创建地址
        address = super().create(validated_data)
        # 返回地址
        return address

